/*
 * IndexBufferImpl.h
 *
 *  Created on: 2011/06/25
 *      Author: naoki
 */

#ifndef INCLUDED_NTENGINE_GRAPHICS_INDEXBUFFERIMPL_H
#define INCLUDED_NTENGINE_GRAPHICS_INDEXBUFFERIMPL_H

#include "NTEngine/Graphics/IndexBuffer.h"
#include "NTEngine/Xml/Element.h"
#include "NTEngine/Xml/Attribute.h"
#include "NTEngine/Base/RefString.h"
#include "NTEngine/Base/ReferenceCounter.h"
#include <GLES2/gl2.h>

namespace NTEngine {
using namespace Xml;
namespace Graphics {

//
class IndexBuffer::Impl : public ReferenceCounter {
public:
	// -------------------------
	Impl( ConstElement e )
	: mObject( 0 )
	, mIndexNumber( 0 )
	, mMapedBuffer( 0 )
	, mName( 0 ) {
		int n = e.childNumber();
		mIndexNumber = n * 3; //三角形数×3
		if ( mIndexNumber > 0 ) {
			createObject();
			unsigned short* indices = lock();
			for ( int i = 0; i < n; ++i ) {
				ConstElement triangle = e.child( i );
				ASSERT( triangle.attributeNumber() > 0 && "IndexBuffer : It's not valid element." );
				ConstAttribute a = triangle.attribute( 0 ); //indices一個しかないので決めうち
				//unsigned shortを取る関数がないのでintに入れてからコピー
				int tmp[ 3 ];
				int count = a.getIntValues( tmp, 3 );
				ASSERT( count == 3 );
				for ( int j = 0; j < 3; ++j ) {
					ASSERT( tmp[ j ] >= 0 && tmp[ j ] <= 0xffff );
					indices[ i * 3 + j ] = static_cast< unsigned short >( tmp[ j ] );
				}
			}
			unlock();
			indices = 0;
		}
		//名前を抜く
		int an = e.attributeNumber();
		for ( int i = 0; i < an; ++i ) {
			ConstAttribute a = e.attribute( i );
			if ( RefString( "name" ) == a.name() ) {
				RefString name( a.value() );
				mName = name.copyOriginal();
			}
		}
	}

	// --------------------------
	Impl( int indexNumber )
	: mObject( 0 )
	, mIndexNumber( indexNumber )
	, mMapedBuffer( 0 )
	, mName( 0 ) {
		createObject();
	}

	~Impl() {
		SAFE_DELETE_ARRAY( mName );
		SAFE_DELETE_ARRAY( mMapedBuffer ); // 必要ないが念のため
		glDeleteBuffers( 1, &mObject );
		mObject = 0;
	}

	unsigned short* lock() {
		ASSERT( mMapedBuffer == 0 );
		mMapedBuffer = NEW unsigned short[ mIndexNumber ];
		return mMapedBuffer;
	}

	void unlock() {
		ASSERT( mMapedBuffer );
		glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mObject );
		glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, sizeof( unsigned short ) * mIndexNumber, mMapedBuffer );
		SAFE_DELETE_ARRAY( mMapedBuffer );
	}

	// メモリを確保
	void createObject() {
		// バッファオブジェクトをもらう
		glGenBuffers( 1, &mObject );
		// 未初期化でバッファを予約しておく
		glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mObject );
		const GLint bufferSize = sizeof( unsigned short ) * mIndexNumber;
		glBufferData( GL_ELEMENT_ARRAY_BUFFER, bufferSize, 0, GL_STATIC_DRAW );
		// バッファサイズを検証
		GLint allocatedBufferSize = 0;
		glGetBufferParameteriv( GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &allocatedBufferSize );
		HARD_ASSERT( bufferSize == allocatedBufferSize );
	}

	GLuint mObject; // GLオブジェクト
	int mIndexNumber; // 頂点数
	unsigned short* mMapedBuffer;
	char* mName;

private:
	void operator=( const Impl& ); // 禁止
};

} // namespace Graphics
} // namespace NtEngine

#endif // INCLUDED_NTENGINE_GRAPHICS_INDEXBUFFERIMPL_H
